//////////////////////////////////////////////////////////////////////////
// ConnecterManager.cpp													//
//																		//
// WYJ																	//
// 2010.4																//
//																		//
//////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "ConnecterManager.h"
#include <assert.h>
#include "Connecter.h"
#include "MessageHandler.h"

#define PORT			5333
#define MAX_CONNECTER	2000
#define MSGSIZE			1024
#define WM_CONNECTERNOTIFY WM_USER + 101

DWORD WINAPI ReceiveThread( LPVOID lpParam )
{
	ConnecterManager* pConnecterManager = (ConnecterManager *)lpParam;

	int            i;
	fd_set         fdread;
	int            ret;
	struct timeval tv = {1, 0};
	char           szMessage[MSGSIZE];

	while (TRUE)
	{
		FD_ZERO(&fdread);
		for (i = 0; i < pConnecterManager->GetConnecterNum(); i++)
		{
			FD_SET( pConnecterManager->GetConnecter( i )->sock, &fdread );
		}

		// We only care read event
		ret = select( 0, &fdread, NULL, NULL, &tv );

		if (ret == 0)
		{
			// Time expired
			continue;
		}

		for ( i = 0; i < pConnecterManager->GetConnecterNum(); i++ )
		{
			if ( FD_ISSET( pConnecterManager->GetConnecter( i )->sock, &fdread ) )
			{
				// A read event happened on g_CliSocketArr[i]
				ret = recv( pConnecterManager->GetConnecter( i )->sock, szMessage, MSGSIZE, 0 );
				if ( ret == 0 || ( ret == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET ) )
				{
					// Client socket closed
					pConnecterManager->RemoveConnecter( i );
				}
				else
				{
					// We received a message from client
					pConnecterManager->DispatchMessage( i, szMessage );
				}
			}
		}
	}

	return 0;
}

DWORD WINAPI ListenThread( LPVOID lpParam )
{
	ConnecterManager* pConnecterManager = (ConnecterManager *)lpParam;

	WSADATA		wsaData;
	SOCKET		sListen;
	SOCKET		sConnecter;
	SOCKADDR_IN	connecter;
	int         iaddrSize = sizeof(SOCKADDR_IN);
	DWORD		dwReceiveThreadId;

	if ( WSAStartup( 0x0202, &wsaData ) )
	{
		
	}
	sListen = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
	pConnecterManager->SetListenSocket( sListen );
	bind(sListen, (struct sockaddr *)pConnecterManager->GetListenAddr(), sizeof(SOCKADDR_IN));

	listen( sListen, 3 );

	CreateThread(NULL, 0, ReceiveThread, pConnecterManager, 0, &dwReceiveThreadId); 
	pConnecterManager->SetReceiveThreadID( dwReceiveThreadId );

	while (TRUE)
	{
		// Accept a connection
		sConnecter = accept( sListen, (struct sockaddr *)&connecter, &iaddrSize );
		pConnecterManager->AddConnecter( sConnecter, &connecter );
	}

	return 0;
}

///////////////////////////////////////////////////////////////////////////////////

ConnecterManager::ConnecterManager( void )
: m_ConnecterNum( 0 ), m_Connecter( NULL ), m_AddrMapNum( 0 ), m_ListenSocket( NULL ),
  m_ListenThreadID( 0 ), m_ReceiveThreadID( 0 ), m_pMessageHandler( NULL ), m_hWnd( NULL )
{
	m_ListenAddr.sin_addr.S_un.S_addr = htonl( INADDR_ANY );
	m_ListenAddr.sin_family = AF_INET;
	m_ListenAddr.sin_port = htons( PORT );
}

ConnecterManager::~ConnecterManager( void )
{
	m_Mutex.Lock();
	for ( AddrMapIter iter = m_AddrMap.begin(); iter != m_AddrMap.end(); iter++ )
	{
		for ( ThreadMapIter i = iter->second.begin(); i != iter->second.end(); i++ )
		{
			if ( i->second->status != e_Close )
			{
				closesocket( i->second->sock );
			}
			delete i->second;
		}
	}
	delete [] m_Connecter;
	m_Mutex.Unlock();

	if ( m_pMessageHandler )
	{
		delete m_pMessageHandler;
	}
}
bool ConnecterManager::Initialize( void )
{
	assert( m_pMessageHandler == NULL );
	m_pMessageHandler = new MessageHandler( this );

	assert( m_Connecter == NULL );
	m_Connecter = new Connecter*[MAX_CONNECTER];
	if ( !m_Connecter )
	{
		char buf[1024];
		sprintf_s( buf, 1024, "Initialize connecter manager failed." );
		MessageBox( NULL, buf, 0, 0 );
		return false;
	}

	CreateThread( NULL, 0, ListenThread, this, 0, &m_ListenThreadID );
	return true;
}

void ConnecterManager::SetListenSocket( SOCKET sock )
{
	m_ListenSocket = sock;
}

const SOCKADDR_IN* ConnecterManager::GetListenAddr( void )
{
	return &m_ListenAddr;
}

void ConnecterManager::AddConnecter( SOCKET sock, const SOCKADDR_IN* addr )
{
	if ( m_ConnecterNum >= MAX_CONNECTER )
	{
		char buf[1024];
		sprintf_s( buf, 1024, "Add a new connecter failed for over the max connecter number %d", MAX_CONNECTER );
		MessageBox( NULL, buf, 0, 0 );
	}

	m_Mutex.Lock();
	m_Connecter[m_ConnecterNum] = new Connecter;
	m_Connecter[m_ConnecterNum]->sock = sock;
	memcpy( m_Connecter[m_ConnecterNum]->ip, inet_ntoa( addr->sin_addr ), 16 );
	m_Connecter[m_ConnecterNum]->thread_id = 0;
	m_Connecter[m_ConnecterNum]->status = e_None;
	m_ConnecterNum++;
	m_Mutex.Unlock();
}

void ConnecterManager::SetReceiveThreadID( DWORD threadID )
{
	m_ReceiveThreadID = threadID;
}

int	ConnecterManager::GetConnecterNum( void )
{
	return m_ConnecterNum;
}

Connecter* ConnecterManager::GetConnecter( int index )
{
	return index >= m_ConnecterNum ? NULL : m_Connecter[index];
}

bool ConnecterManager::RemoveConnecter( int index )
{
	if ( index >= m_ConnecterNum )
	{
		char buf[1024];
		sprintf_s( buf, 1024, "Remove a not exist connect index %d", index );
		MessageBox( NULL, buf, 0, 0 );
	}
	
	m_Mutex.Lock();
	if ( m_Connecter[index]->status == e_Close )
	{
		char buf[1024];
		sprintf_s( buf, 1024, "Remove a closed connect index %d", index );
		MessageBox( NULL, buf, 0, 0 );
		m_Mutex.Unlock();
		return false;
	}
	closesocket( m_Connecter[index]->sock );
	m_Connecter[index]->status = e_Close;
	Notify( m_Connecter[index] );
	m_Connecter[index] = m_Connecter[--m_ConnecterNum];
	m_Connecter[m_ConnecterNum] = NULL;
	m_Mutex.Unlock();

	return true;
}

void ConnecterManager::DispatchMessage( int index, const char * msg )
{
	m_pMessageHandler->HandleMessage( index, msg );
}

bool ConnecterManager::InitConnecter( int index, DWORD threadID )
{
	if ( index >= m_ConnecterNum )
	{
		char buf[1024];
		sprintf_s( buf, 1024, "Initialize a not exist connect index %d", index );
		MessageBox( NULL, buf, 0, 0 );
	} 

	m_Mutex.Lock();
	m_Connecter[index]->thread_id = threadID;
	m_Connecter[index]->status = e_Ready;
	AddrMapIter iter = m_AddrMap.find( inet_addr( m_Connecter[index]->ip ) );
	if ( iter == m_AddrMap.end() )
	{
		m_AddrMap.insert( AddrMap::value_type( inet_addr( m_Connecter[index]->ip ), ThreadMap() ) );
		iter = m_AddrMap.find( inet_addr( m_Connecter[index]->ip ) );
	}
	if ( iter != m_AddrMap.end() )
	{
		ThreadMapIter i = iter->second.find( threadID );
		if ( i != iter->second.end() )
		{
			delete i->second;
			i->second = m_Connecter[index];
		}
		else
		{
			iter->second.insert( ThreadMap::value_type( threadID, m_Connecter[index] ) );
		}
		Notify( m_Connecter[index] );
	}
	m_Mutex.Unlock();

	return true;
}

void ConnecterManager::SetHwnd( HWND hWnd )
{
	m_hWnd = hWnd;
}

Connecter* ConnecterManager::GetConnecter( unsigned long addr, DWORD threadID )
{
	AddrMapIter iter = m_AddrMap.find( addr );
	if ( iter != m_AddrMap.end() )
	{
		ThreadMapIter i = iter->second.find( threadID );
		if ( i != iter->second.end() )
			return i->second;
	}
	return NULL;
}

void ConnecterManager::Notify( Connecter* pConnecter )
{
	SendMessage( m_hWnd, WM_CONNECTERNOTIFY, (WPARAM)0, (LPARAM)pConnecter );
}